// 待完善
#ifndef xpack_graphic_box_layer
#define xpack_graphic_box_layer
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::graphic_box_layer::inc
#include"define/base_type.hpp"
#include"define/classify.hpp"
#include"dumb/struct_type.hpp"
#include"macro/xcstyle.hpp"
#include"macro/xexport.hpp"
#include"macro/xstruct.hpp"
#include"macro/xmodify.hpp"
#include"math/point.hpp"
#include"math/size.hpp"
#include"meta/has_cast.hpp"
#include"meta/is_same.hpp"
#include"utils/array.hpp"
#pragma pop_macro("xuser")

namespace mixc::graphic_box_layer::inc{
    using std_pt2x      = inc::pt2wx;
    using std_sz2       = inc::sz2w;

    xstruct(
        xname(basic_info)
    )
        std_pt2x    start               = {};
        std_sz2     size                = {};
    $

    template<uxx dummy_v>
    xstruct(
        xtmpl(ui_dummy, dummy_v)
    )
        static constexpr bool im_graphic_box_layer_ui_dummy = true;
    $

    template<class type_t>
    struct select{
        using result = inc::struct_type<type_t>;
    };

    template<uxx dummy_v>
    struct select<ui_dummy<dummy_v>>{
        using result = ui_dummy<dummy_v>;
    };

    template<class type_t>
    using param_base = typename select<type_t>::result;
}

namespace mixc::graphic_box_layer{
    // enum class id_t : i16{
    //     none,
    // };
    using id_t = u16;

    // 对于 ui_panel 的布局枚举
    enum class direction_t : u08{
        left_to_right,
        right_to_left,
        top_to_bottom,
        bottom_to_top,
    };

    enum class location_t : u08{
        left,
        top,
        right,
        bottom,
        left_bottom,
        left_top,
        right_top,
        right_botom,
        middle,
    };

    #define xgen_float(NAME)                \
    xstruct(                                \
        xname(NAME)                         \
    )                                       \
        float value;                        \
        NAME(auto value) :                  \
            value((f32)value){              \
        }                                   \
        operator float &(){                 \
            return value;                   \
        }                                   \
    $

    enum class w_t : u16{};
    enum class h_t : u16{};

    enum class width_t : u16{};
    enum class height_t : u16{};

    xgen_float(width_percent_t);
    xgen_float(height_percent_t);

    enum class rows_t : u16{};
    enum class columns_t : u16{};

    enum class padding_t : u16{};
    enum class padding_left_t : u16{};
    enum class padding_top_t : u16{};
    enum class padding_right_t : u16{};
    enum class padding_bottom_t : u16{};
    enum class margin_t : u16{};
    enum class margin_left_t : u16{};
    enum class margin_top_t : u16{};
    enum class margin_right_t : u16{};
    enum class margin_bottom_t : u16{};

    enum class visiable_t : u08{};

    enum class cell_padding_t : u16{};

    enum class same_width_height_t : u08{};

    enum class width_ref_height_minus_t : u16{};
    enum class width_ref_height_plus_t : u16{};
    enum class height_ref_width_minus_t : u16{};
    enum class height_ref_width_plus_t : u16{};

    #undef xgen_float

    constexpr auto operator "" _w(u64 value){
        return width_t(value);
    }

    constexpr auto operator "" _h(u64 value){
        return height_t(value);
    }

    constexpr auto _w                   = w_t{};
    constexpr auto _h                   = h_t{};
    constexpr auto same_width_height    = same_width_height_t{};

    inline auto operator % (f64 value, w_t){
        return width_percent_t(value);
    }

    inline auto operator % (f64 value, h_t){
        return height_percent_t(value);
    }

    constexpr auto operator "" _row(u64 value){
        return rows_t(value);
    }

    constexpr auto operator "" _col(u64 value){
        return columns_t(value);
    }

    constexpr auto operator "" _pd(u64 value){ return padding_t(value); }
    constexpr auto operator "" _pdl(u64 value){ return padding_left_t(value); }
    constexpr auto operator "" _pdt(u64 value){ return padding_top_t(value); }
    constexpr auto operator "" _pdr(u64 value){ return padding_right_t(value); }
    constexpr auto operator "" _pdb(u64 value){ return padding_bottom_t(value); }

    constexpr auto operator "" _mg(u64 value){ return margin_t(value); }
    constexpr auto operator "" _mgl(u64 value){ return margin_left_t(value); }
    constexpr auto operator "" _mgt(u64 value){ return margin_top_t(value); }
    constexpr auto operator "" _mgr(u64 value){ return margin_right_t(value); }
    constexpr auto operator "" _mgb(u64 value){ return margin_bottom_t(value); }

    static constexpr id_t no_ref = {};

    enum class vedge_t : u08{
        left,
        right,
    };

    enum class hedge_t : u08{
        top,
        bottom,
    };

    enum class docker_t : u08{
        panel,
        table,
        tablecell,
    };

    #define xgen(NAME,EDGE)                         \
    xstruct(                                        \
        xname(NAME)                                 \
    )                                               \
        id_t                i_ref = {};             \
        EDGE                edge;                   \
    $

    xgen(align_l, vedge_t);     // 当前 box 以左边为对齐边，和 i_ref 指向的 box 的指定 edge 进行对齐
    xgen(align_t, hedge_t);     // 当前 box 以上边为对齐边，和 i_ref 指向的 box 的指定 edge 进行对齐
    xgen(align_r, vedge_t);     // 当前 box 以右边为对齐边，和 i_ref 指向的 box 的指定 edge 进行对齐
    xgen(align_b, hedge_t);     // 当前 box 以下边为对齐边，和 i_ref 指向的 box 的指定 edge 进行对齐
    #undef  xgen

    struct margin{
        id_t                i_ref       = no_ref;
        u16                 value       = 0;
    };

    struct margin_lr{
        margin              left;
        margin              right;
    };

    struct margin_tb{
        margin              top;
        margin              bottom;
    };

    struct margin_ltrb{
        margin              left;
        margin              top;
        margin              right;
        margin              bottom;
    };

    typedef struct docker_base_info : inc::basic_info {
        id_t                id              = {};
        align_l             align_left      = {};
        align_t             align_top       = {};
        align_r             align_right     = {};
        align_b             align_bottom    = {};
        margin_ltrb         margin          = {};
        inc::std_pt2x       cursor          = {};
    } * docker_base_infop;

    struct panel_info : docker_base_info{
        direction_t         direction       = direction_t::left_to_right;
    };

    struct table_info : docker_base_info{

    };

    template<class ... args_t>
    xstruct(
        xtmpl(params, args_t...),
        xpubb(inc::param_base<args_t> ...)
    )
        constexpr params(args_t && ... value) : 
            inc::param_base<args_t>((args_t &&)value)... {
        }

        // params 将属性转换成 param_base<> 包装的基类，这要求基类不能有重复的属性
        // 
        // has_attribute 只判断当前节点是否包含指定类型的属性，
        // 而非它的子节点包含某个属性，由于继承的传递性
        // 如果 C based_on B, B based_on A，那么 C is_based_on A = true
        // 这样会导致外部错误的把 A 的属性当作 C 的属性，所以 params<> 的子类应该使用私有继承
        // 并且这里使用 has_cast 表示当前节点是否存在 type_t 类型的属性
        template<class type_t>
        static constexpr bool has_attribute = 
            inc::has_cast<
                inc::param_base<type_t> *, the_t *
            >;

        template<class type_t>
        type_t & get(){
            inc::param_base<type_t> * base = this;
            return *base;
        }
    $

    template<class ... args_t>
    // TODO: requires()
    xstruct(
        xtmpl(ui_panel, args_t...),
        xprib(params<args_t...>), // 使用私有继承，参考 params::has_attribute 定义
        xwhos(inc::classify_t::graphic_box_layer_ui_panel)
    )
        constexpr ui_panel(args_t && ... args) :
            params<args_t...>((args_t &&)args...){
        }
    $

    template<class ... args_t>
    // 必须包含 rows_t 和 columns_t
    // 可选包含 width_t/height_t
    // requires(
    //     inc::is_same<rows_t, table_rows_t> and
    //     inc::is_same<columns_t, table_columns_t>
    // )
    xstruct(
        xtmpl(ui_table, args_t...),
        xprib(params<args_t...>), // 使用私有继承，参考 params::has_attribute 定义
        xwhos(inc::classify_t::graphic_box_layer_ui_table)
    )
        constexpr ui_table(args_t && ... args) :
            params<args_t...>((args_t &&)args...){
        }
    $

    template<class ... args_t>
    // TODO: requires
    xstruct(
        xtmpl(ui_tablecell, args_t...),
        xprib(params<args_t...>), // 使用私有继承，参考 params::has_attribute 定义
        xwhos(inc::classify_t::graphic_box_layer_ui_tablecell)
    )
        constexpr ui_tablecell(args_t && ... args) :
            params<args_t...>((args_t &&)args...){
        }
    $

    template<uxx rows_v, uxx columns_v, class ... args_t>
    constexpr auto table_entity(args_t && ... default_paramss){
        using item_t        = params<args_t &&...>;
        using ary_t         = inc::array<item_t, rows_v, columns_v>;
        ary_t   ary;
        item_t  param(default_paramss...);

        for(uxx i = 0; i < rows_v; i++){
            for(uxx j = 0; j < columns_v; j++){
                ary[i][j]   = param;
            }
        }
        return ary;
    }

    void temprh_demo(){
        enum : uxx{
            __ui_dummy_begin = __COUNTER__,
        };

        //#define xui_panel(...)              ui_panel{ inc::ui_dummy<__COUNTER__ - __ui_dummy_begin>{}, // 加 ui_dummy 是为了保证这个类型唯一性，而不会导致多继承时候冲突
        //#define xui_tab(...)                ui_table{ inc::ui_dummy<__COUNTER__ - __ui_dummy_begin>{}, // 加 ui_dummy 是为了保证这个类型唯一性，而不会导致多继承时候冲突
        //#define xui_tabcell(...)            ui_tablecell{ inc::ui_dummy<__COUNTER__ - __ui_dummy_begin>{}, // 加 ui_dummy 是为了保证这个类型唯一性，而不会导致多继承时候冲突

        #define xui     inc::ui_dummy<__COUNTER__ - __ui_dummy_begin>{}, // 加 ui_dummy 是为了保证这个类型唯一性，而不会导致多继承时候冲突

        enum : id_t{
            i_id_temp_sign = 1,
            i_id_temp_int_part0,
            i_id_temp_int_part1,
            i_id_temp_dec_part0,
            i_id_max,
        };

        auto && root = ui_panel{
            xui direction_t::left_to_right, 100%_w, 30%_h,

            // 如果没有指定宽高，则判断 table_cell 是否指定，table_cell 的宽高必须是具体值
            // 若：table 没有指定宽高
            //    若：table_cell 指定 _w _h
            //      整个表格的大小在不超过父容器大小的情况下(饱和运算)
            //      ui_table.w = cell.w * col + margin * (col - 1) + ui_table.pdl + ui_table.pdr
            //      ui_table.h = cell.h * row + margin * (row - 1) + ui_table.pdt + ui_table.pdb
            //    否: 当前 ui_table 下的所有 table_cell 平均宽高，并占满整个父节点
            // 否：table_cell 默认居中显示，边缘超过的部分将被遮挡(默认，可以考虑显示)
            //
            // * 子元素的绘制方向控制遮挡部分
            // * padding 不能超过本身的大小
            // * 如果当前 panel 设置 left_to_right 布局，那么当前 panel 的子节点无法使用 vedge_t 对齐方式，但子节点的子节点则是以自己的父节点为参考对象
            // +/-
            ui_table{
                xui i_id_temp_sign, 5_row, 3_col,

                // 单元格模板
                ui_tablecell{
                    xui 5_w, 5_h, 1_mg,

                    // 将当前 box 的 top 边和 i_id_temp_int_part0 对应的 box 的 top 边为对齐
                    align_t{ .i_ref = i_id_temp_int_part0, .edge = hedge_t::top },
                },
            },

            // temp int bit1
            ui_table{
                xui i_id_temp_int_part0, 5_row, 3_col, 4_mgr, ui_tablecell{ xui 10_w, 10_h, 1_mg }
            },

            // temp int bit0
            ui_table{
                xui i_id_temp_int_part1, 5_row, 3_col, 4_mgr, ui_tablecell{ xui 10_w, 10_h, 1_mg }
            },

            // temp dec bit0
            ui_table{
                xui i_id_temp_dec_part0, 5_row, 3_col, ui_tablecell{
                    xui 5_w, 5_h, 1_mg,

                    // 将当前 box 的 bttom 边和 i_id_temp_int_part0 对应的 box 的 bottom 边为对齐
                    align_b{ .i_ref = i_id_temp_int_part0, .edge = hedge_t::bottom }
                },
            },
            
            // temp degree flag
            // 如果不需要运行时调整此 box，可以不赋予 id
            ui_table{
                xui 1_row, 1_col, ui_tablecell{
                    xui 5_w, 5_h, 1_mg,

                    // 将当前 box 的 top 边和 i_id_temp_int_part0 对应的 box 的 top 边为对齐
                    align_b{ .i_ref = i_id_temp_int_part0, .edge = hedge_t::top }
                },
            },
        };
    }

    struct parser{
        void run(uxx max_id, auto & root){
            m_info_list = inc::array<inc::basic_info>(
                length(max_id)
            );
        }
    
    private:
        template<
            template<class ...> class tuple_t, class ... args_t
        >
        void foreach(auto & parent, tuple_t<args_t...> & node){
            using node_t = tuple_t<args_t...>;
            if constexpr (inc::is_ui_panel<node_t>){
                
            }
            else if constexpr (inc::is_ui_table<node_t>){
                
            }
        }

        #define xui_if_has(TYPE)                    if constexpr (node.template has_attribute<TYPE>)
        #define xui_get(TYPE)                       (TYPE &)node.template get<TYPE>()
        #define xui_getx(TYPE,ATTR,...)             xui_if_has(TYPE) { ATTR = xui_get(TYPE) __VA_ARGS__; }

        template<bool is_disable_tb_v, bool is_disable_lr_v>
        auto layout_align(){

        }

        template<class parent_info_t, class node_t>
        auto layout(parent_info_t & parent_info, node_t & node){
            auto panel              = panel_info{};
            auto table              = table_info{};
            auto basic              = docker_base_infop{};

            if constexpr (inc::is_ui_panel<node_t>){
                basic           = xmodify(panel);
            }
            else if constexpr (inc::is_ui_table<node_t>){
                basic           = xmodify(table);
            }
            else{
                return;
            }

            // 获取 size，默认继承父类大小
            auto & size             = basic->size;
            size                    = parent_info.size;

            xui_if_has(width_t){
                size->width         = uxx(xui_get(width_t));
            }
            else xui_if_has(width_percent_t){
                auto percent        = xui_get(width_percent_t);
                auto value          = uxx(parent_info.size->width * percent);
                size->width         = value;
            }

            xui_if_has(height_t){
                size->height        = uxx(xui_get(height_t));
            }
            else xui_if_has(height_percent_t){
                auto percent        = xui_get(height_percent_t);
                auto value          = uxx(parent_info.size->height * percent);
                size->height        = value;
            }

            xui_getx(id_t,      basic->id);
            xui_getx(align_l,   basic->align_left);
            xui_getx(align_t,   basic->align_top);
            xui_getx(align_r,   basic->align_right);
            xui_getx(align_b,   basic->align_bottom);

            // 
            if constexpr (inc::is_same<parent_info_t, panel_info>){
                panel_info * info = &parent_info;

                // 限制：
                // 对于 left <-> right 水平方向布局，
                // 两个相邻的元素只可以相切或者相离，不能相交/重合/包含，以及与布局顺序对应的位置冲突，
                // 比如从左往右布局，那么下一个元素必须在前一个元素的右边
                switch(info->direction){
                case direction_t::left_to_right:
                    break;
                case direction_t::right_to_left:
                    break;
                case direction_t::top_to_bottom:
                    break;
                // case direction_t::bottom_to_top:
                default:
                    break;
                }
            }
            else if constexpr (inc::is_same<parent_info_t, table_info>){
                
            }
            else{
                return;
            }

            if constexpr (inc::is_ui_panel<node_t>){
                xui_getx(direction_t, panel.direction);
                return panel;
            }
            else if constexpr (inc::is_ui_table<node_t>){

                return table;
            }
        }

        #undef xui_if_has
        #undef xui_get

        inc::std_pt2x               m_origin;
        inc::std_sz2                m_size;
        inc::array<inc::basic_info> m_info_list;
    };
}

namespace mixc::graphic_box_layer::origin::layer{
}

#endif

xexport_spacex(box, mixc::graphic_box_layer::origin)
